package cn.kk.fluidcells.cells.keyboard;

import cn.kk.fluidcells.api.InputEvent;

public class KeyEvent extends InputEvent {

    private static final long serialVersionUID = -5873239025086386167L;

    /** This is used to indicate that the keyCode is unknown. */
    public static final char CHAR_UNDEFINED = 0xFFFF;

    public KeyEvent(Object src, long evtTime, int modifiers, int rawCode, KeyCode keyCode, char keyChar,
            KeyLocation keyLocation) {
        super(src, evtTime, modifiers);

        this.rawCode = rawCode;
        this.keyCode = keyCode;
        this.keyChar = keyChar;
        this.keyLocation = keyLocation;
    }

    private int rawCode;

    private KeyCode keyCode;

    private char keyChar;

    private final KeyLocation keyLocation;

    public static final int NATIVE_KEY_FIRST = 2400;

    public static final int NATIVE_KEY_LAST = 2402;

    public static final int NATIVE_KEY_TYPED = KeyEvent.NATIVE_KEY_FIRST;

    public static final int NATIVE_KEY_PRESSED = 1 + KeyEvent.NATIVE_KEY_FIRST;

    public static final int NATIVE_KEY_RELEASED = 2 + KeyEvent.NATIVE_KEY_FIRST;

    /**
     * Returns the native code associated with the native key in this event. This is an arbitrary number between 0 and
     * 255 (inclusive) used by the operating system to represent a physical key on the keyboard. This code does not
     * necessarily represent the native key's scan code or ascii representation. To maintain platform independence, you
     * should not rely on the consistancy of this value from platform to platform.
     * 
     * @return the native key code for this event.
     */
    public int getRawCode() {
        return this.rawCode;
    }

    /**
     * Set the rawCode value in this event. For more information on what this value represents please see
     * {@link #getRawCode()}.
     * 
     * 
     * 
     * @param rawCode
     *            the native key code for this event.
     */
    public void setRawCode(int rawCode) {
        this.rawCode = rawCode;
    }

    /**
     * Returns the keyCode associated with this event.
     * 
     * @return the native virtual key code.
     */
    public KeyCode getKeyCode() {
        return this.keyCode;
    }

    /**
     * Set the keyCode value in this event.
     * 
     * @param keyCode
     *            the native virtual key code.
     */
    public void setKeyCode(KeyCode keyCode) {
        this.keyCode = keyCode;
    }

    /**
     * Returns the native Unicode character associated with this event.
     * 
     * @return the Unicode character defined for this key event. If no valid Unicode character exists for this key
     *         event, <code>CHAR_UNDEFINED</code> is returned.
     */
    public int getKeyChar() {
        return this.keyChar;
    }

    /**
     * Set the keyChar value in this event. For example, the <code>NATIVE_KEY_TYPED</code> event for Shift + "a" returns
     * the Unicode value 'A'.
     * 
     * @param keyChar
     *            the keyboard character associated with this event.
     */
    public void setKeyChar(char keyChar) {
        this.keyChar = keyChar;
    }

    /**
     * Returns the location of the virtual key for this event.
     * 
     * @return the location of the virtual key that was pressed or released.
     */
    public KeyLocation getKeyLocation() {
        return this.keyLocation;
    }

    @Override
    public String toString() {
        StringBuilder param = new StringBuilder(255);
        if (getModifiers() != 0) {
            param.append(InputEvent.getModifiersText(getModifiers()));
            param.append('+');
        }
        param.append(this.keyCode);
        param.append(", ");

        switch (this.keyChar) {
            case '\b':
            case 0x03:
            case 0x7F:
            case 0x1B:
            case '\n':
            case '\t':
                param.append(KeyCode.fromKeyCode(this.keyChar).getKeyText());
                break;
            case CHAR_UNDEFINED:
                param.append(KeyCode.VK_UNDEFINED.getKeyText());
                break;
            default:
                param.append('\'');
                param.append(this.keyChar);
                param.append('\'');
                break;
        }
        param.append(", ");
        param.append(this.rawCode);
        param.append(", ").append(this.keyLocation);

        return param.toString();
    }
}
